using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using Castle.Core.Interceptor;
using Facebook.Core.Contracts;
using System.Linq;

namespace Facebook.Core
{
    public class ApiCallInterceptor : IInterceptor
    {
        public string ApiKey { get; set; }
        public string Secret { get; set; }
        public IFacebookSessionManager FacebookSessionManager { get; set; }

        public ApiCallInterceptor(string apiKey, string secret, IFacebookSessionManager facebookSessionManager)
        {
            ApiKey = apiKey;
            Secret = secret;
            FacebookSessionManager = facebookSessionManager;
        }

        public void Intercept(IInvocation invocation)
        {
            IApiCaller apiCaller = invocation.InvocationTarget as IApiCaller;
            if(apiCaller == null)
                return;


            List<ApiCall> apiCallAttributes = ((ApiCall[])invocation.Method.GetCustomAttributes(typeof(ApiCall) ,true)).ToList();
            if(apiCallAttributes.Count == 0)
                return;

            apiCaller.GeneratedTicks = DateTime.Now.Ticks;

            ParameterInfo[] parameters = invocation.Method.GetParameters();

            SortedDictionary<string, string> parameterDictionary = new SortedDictionary<string, string>();

            for (int i = 0; i < parameters.Length; i++)
            {
                parameterDictionary.Add(parameters[i].Name, invocation.Arguments[i].ToString());
            }

            parameterDictionary.Add("api_key", ApiKey);
            if (apiCallAttributes[0].HasSession) 
                parameterDictionary.Add("session_key", FacebookSessionManager.GetSession());
            parameterDictionary.Add("v", "1.0");
            if (apiCallAttributes[0].HasSession)
                parameterDictionary.Add("call_id", apiCaller.GeneratedTicks.ToString());
            
            string method = apiCallAttributes[0].Method;
            Regex regex = new Regex(@"\?method=(?<methodName>[a-zA-Z0-9.]*)");
            Match match = regex.Match(method);
            method = match.Groups["methodName"].Value;

            parameterDictionary.Add("method", method);

            apiCaller.GeneratedSignature = GenerateHash(parameterDictionary);
            apiCaller.ApiKey = ApiKey;
            apiCaller.SessionKey = FacebookSessionManager.GetSession();

            try
            {
                invocation.Proceed();
            }
            catch (Exception e)
            {
                
            }
        }

        private string GenerateHash(SortedDictionary<string, string> parameters)
        {
            StringBuilder builder = new StringBuilder();

            foreach (var pair in parameters)
            {
                builder.Append(String.Format(CultureInfo.InvariantCulture, "{0}={1}", pair.Key, pair.Value));
            }

            string sig = builder.Append(Secret).ToString();

            return GetMD5Hash(sig);
        }

        public string GetMD5Hash(string input)
        {
            var md5Crypto = new MD5CryptoServiceProvider();
            byte[] data = md5Crypto.ComputeHash(Encoding.UTF8.GetBytes(input));

            // convert the result to hex and return
            var md5HashToReturn = new StringBuilder();
            for (int i = 0; i < data.Length; i++) md5HashToReturn.Append(data[i].ToString("x2"));
            return md5HashToReturn.ToString().ToLower();
        }
    }
}